package gateway02.config;

import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import common05.common.Token;
import gateway02.handler.JwtSecurityAccessDeniedHandler;
import gateway02.handler.JwtSecurityAuthenticationHandler;
import gateway02.handler.SecurityAccessDeniedHandler;
import gateway02.handler.SecurityAuthenticationHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.*;
import org.springframework.security.web.server.SecurityWebFilterChain;

import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

@EnableWebFluxSecurity
public class SecurityConfig {

    @Value("${jwt.public.key}")
    private RSAPublicKey publicKey;

    @Value("${jwt.private.key}")
    private RSAPrivateKey privateKey;

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http.csrf().disable();
        http.authorizeExchange().pathMatchers(Token.JWT_PERMIT_ALL_URL).permitAll();
        http.authorizeExchange().anyExchange().authenticated();
        http.httpBasic().disable();
        http.formLogin().disable();
        http.logout().disable();

        http.exceptionHandling().accessDeniedHandler(new SecurityAccessDeniedHandler());
        http.exceptionHandling().authenticationEntryPoint(new SecurityAuthenticationHandler());

        http.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtDecoder(reactiveJwtDecoder()))
                .accessDeniedHandler(new JwtSecurityAccessDeniedHandler())
                .authenticationEntryPoint(new JwtSecurityAuthenticationHandler()));

        return http.build();
    }

    @Bean
    public ReactiveJwtDecoder reactiveJwtDecoder() {
        return NimbusReactiveJwtDecoder.withPublicKey(this.publicKey).build();
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withPublicKey(this.publicKey).build();
    }

    @Bean
    public JwtEncoder jwtEncoder() {
        JWK jwk = new RSAKey.Builder(this.publicKey).privateKey(this.privateKey).build();
        JWKSource<SecurityContext> jwkSet = new ImmutableJWKSet<>(new JWKSet(jwk));
        return new NimbusJwtEncoder(jwkSet);
    }


}
